﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BEPUphysics.Entities;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Asplode.GameEntity.Characters;

namespace Asplode
{
    public class GameObjectFactory
    {
        private Game game;

        public GameObjectFactory(Game game)
        {
            this.game = game;
        }

        public Zombie AddZombie(Vector3 position)
        {
            GameObject characterGameObject = AddGameObject(GameObject.Type.PLAYER, position, Vector3.Zero);
            Zombie zombie = new Zombie(characterGameObject);
            return zombie;
        }

        public Character AddHuman(Vector3 position)
        {
            GameObject characterGameObject = AddGameObject(GameObject.Type.PLAYER, position, Vector3.Zero);
            Character character = new Human(characterGameObject);
            return character;
        }

        public GameObject AddGameObject(GameObject.Type type, Vector3 position)
        {
            return AddGameObject(type, position, Vector3.Zero);
        }

        public GameObject AddStaticBox(Vector3 position, float width, float height, float length)
        {
            //Make a box representing the ground and add it to the space.
            //The Box is an "Entity," the main simulation object type of BEPUphysics.
            //Examples of other entities include cones, spheres, cylinders, and a bunch more (a full listing is in the BEPUphysics.Entities namespace).

            //Every entity has a set of constructors.  Some half a parameter for mass, others don't.
            //Constructors that allow the user to specify a mass create 'dynamic' entiites which fall, bounce around, and generally work like expected.
            //Constructors that have no mass parameter create a create 'kinematic' entities.  These can be thought of as having infinite mass.
            //This box being added is representing the ground, so the width and length are extended and it is kinematic.
            Box body = new Box(Vector3.Zero, width, height, length);

            game.physics.add(body);
            //This 1x1x1 cube model will represent the box entities in the space.
            Model model = game.Content.Load<Model>("Models\\cube");

            Matrix scaling = Matrix.CreateScale(width, height, length); //Since the cube model is 1x1x1, it needs to be scaled to match the size of each individual box.
            GameObject gameObject = new GameObject(body, model, scaling, game);
            //Add the drawable game component for this entity to the game.
            game.Components.Add(gameObject);
            body.tag = model; //set the object tag of this entity to the model so that it's easy to delete the graphics component later if the entity is removed.

            return gameObject;
        }

        public GameObject AddGameObject(GameObject.Type type, Vector3 position, Vector3 acceleration)
        {
            Entity body;
            Model model;
            Matrix scaling;

            if (GameObject.Type.PROJECTILE == type)
            {
                Box box = new Box(position, 1, 1, 1, 0.2f);

                //This 1x1x1 cube model will represent the box entities in the space.
                model = game.Content.Load<Model>("Models\\cube");

                scaling = Matrix.CreateScale(box.width, box.height, box.length);

                body = box;
            }
            else if (GameObject.Type.PLAYER == type)
            {
                float radius = 1;
                float diameter = radius * 2;
                Cylinder cylinder = new Cylinder(position + new Vector3(0, radius, 0), radius * 2, radius, (float)Math.Pow(radius, 3));

                // This model is centered at 0,0,0 and is 1 unit wide and 1 unit tall.
                model = game.Content.Load<Model>("Models\\character");

                // If radius is 1, the model needs to be scaled by a factor of 2 in the x and y directions.
                scaling = Matrix.CreateScale(cylinder.radius * 2, cylinder.height, cylinder.radius * 2);

                body = cylinder;
            }
            else
            {
                return null;
            }

            game.physics.add(body);
            body.applyImpulse(position, acceleration * body.mass);

            GameObject entityModel = new GameObject(body, model, scaling, game);
            //Add the drawable game component for this entity to the game.
            game.Components.Add(entityModel);
            body.tag = entityModel;
            return entityModel;
        }
    }
}
